{
  // ------------------------------联合类型和类型保护
  interface Bird {
    fly: boolean
    sing: () => {}
  }

  interface Dog {
    fly: boolean
    bark: () => {}
  }

  // 类型保护、三种方法
  //1、类型断言的方式类型保护
  // function trainAnial(animal: Bird | Dog) {
  //   if (animal.fly) {
  //     ;(animal as Bird).sing()
  //   } else {
  //     ;(animal as Dog).bark()
  //   }
  // }

  //2、  in  语法 来做类型保护
  function trainAnialSecond(animal: Bird | Dog) {
    if ('sing' in animal) {
      animal.sing()
    } else {
      animal.bark()
    }
  }

  //3、 typeof 做类型保护
  function add(first: string | number, second: string | number) {
    if (typeof first === 'string' || typeof second === 'string') {
      return `${first}${second}`
    }
    return first + second
  }

  // console.log(add('333', 123))
}

// ------------------------------枚举类型
{
  //枚举会递归的
  // 默认的枚举 enum   从  0 开始  到 123456
  // 在OFFLINE  = 1  从1开始   从ONLINE = 4    下面就是 5
  // 注意：enum 枚举类型 赋值的话    OFFLINE=1  Statusp[1]  开始  否则会unidentified
  enum Status {
    OFFLINE,
    ONLINE,
    DELETED,
  }
  // console.log(Status[0], 'enum')
}

// ------------------------------泛型
{
  //1、必须传指定类型
  function join<T, P>(first: T, second: P) {
    return `${first}${second}`
  }
  join(1, '123') //TS会自行 推导
  // join<number, string>(1, '123')  //类型注解

  //2、类型区别  数组string[]  等同Array<T>
  function map<T>(params: Array<T>) {
    return params
  }
  // map<string>(['123'])
  // console.log(map<string>(['123']))
}

// ---------------------------类中的泛型以及 泛型类型
{
  interface Item {
    name: string
  }

  class DateManager<T extends Item> {
    constructor(private data: T[]) {}
    getItem(index: number): T {
      return this.data[index]
    }
  }

  const data = new DateManager([{ name: 'dell' }])
  // console.log(data.getItem(0), ' data')

  //如何使用泛型作为一个具体的类型注解
  const func: <T>(params: T) => T = <T>(params: T) => {
    return params
  }

  // console.log(func(1), 'func')
}

// ---------------------------泛型中的keyof使用
{
  interface Person {
    name: string
    age: number
    gender: string
  }
  class teacher {
    constructor(private info: Person) {}
    getInfo<T extends keyof Person>(key: T): Person[T] {
      return this.info[key]
    }
  }

  const teacher2 = new teacher({
    name: 'dell',
    age: 19,
    gender: 'male',
  })

  const test = teacher2.getInfo('gender') //注意传入的时候必须interface 接口里面有的数据
  // console.log(teacher2, 'tes')
}
